package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.query.album.TrackInfoVo;
import com.atguigu.tingshu.query.album.TrackMediaInfoVo;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.album.TrackStatVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private AlbumInfoService albumInfoService;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private AuditService auditService;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private UserFeignClient userFeignClient;


    /**
     * 保存声音
     *
     * @param trackInfoVo 保存声音信息
     * @return void
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        if (trackInfoVo != null) {
            //1. 线程中获取userId
            Long userId = AuthContextHolder.getUserId();
            //2. 获取专辑信息(专辑封面: 可用作声音默认封面)
            AlbumInfo albumInfo = albumInfoService.getById(trackInfoVo.getAlbumId());
            if (albumInfo == null) {
                log.error("专辑不存在: " + albumInfo);
                throw new GuiguException(404, "未找到该专辑信息");
            }
            //3. 新增声音记录
            //3.1 trackInfoVo对象类型转换: hutool-utils
            TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
            //3.2 完善trackInfo信息内容
            //3.2.1 用户ID
            trackInfo.setUserId(userId);
            //3.2.2 声音序号
            trackInfo.setOrderNum(albumInfo.getIncludeTrackCount() + 1);
            //3.2.3 获取云平台声音详情: 时长,类型,大小
            TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfo.getMediaFileId());
            if (trackMediaInfo != null) {
                trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
                trackInfo.setMediaSize(trackMediaInfo.getSize());
                trackInfo.setMediaType(trackMediaInfo.getType());
            }
            //3.3.4 声音来源: 用户上传
            trackInfo.setSource(SystemConstant.TRACK_SOURCE_USER);
            //3.3.5 审核状态: 待审核
            trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
            //3.3.6 封面: 若无封面,使用专辑默认封面
            String coverUrl = trackInfoVo.getCoverUrl();
            if (coverUrl == null) {
                trackInfo.setCoverUrl(albumInfo.getCoverUrl());
            }

            //3.4 新增声音记录,回显trackId
            trackInfoMapper.insert(trackInfo);
            Long trackId = trackInfo.getId();

            //4 更新专辑声音数量信息
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
            albumInfoService.updateById(albumInfo);

            //5 新增声音统计信息
            this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PLAY, 0);
            this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COLLECT, 0);
            this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_COMMENT, 0);
            this.saveTrackStat(trackId, SystemConstant.TRACK_STAT_PRAISE, 0);

            //6 提交内容审核
            //文本内容审核
            String text = trackInfo.getTrackTitle() + trackInfo.getTrackIntro();
            String suggestion = auditService.auditText(text);
            if ("pass".equals(suggestion)) {
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
                //文本审核通过后，还需要进一步审核音频内容
                String reviewTaskId = auditService.startReviewTask(trackInfo.getMediaFileId());
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
                trackInfo.setReviewTaskId(reviewTaskId);
            } else if ("block".equals(suggestion)) {
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_NO_PASS);
            } else if ("review".equals(suggestion)) {
                trackInfo.setStatus(SystemConstant.TRACK_STATUS_ARTIFICIAL);
            }
            trackInfoMapper.updateById(trackInfo);
        }
    }

    /**
     * 获取当前用户声音分页列表
     *
     * @param albumListVoIPage 分页条件
     * @param trackInfoQuery   查询条件
     * @return 分页结果 albumListVoPage
     */
    @Override
    public IPage<TrackListVo> findUserTrackPage(IPage<TrackListVo> albumListVoIPage,
                                                TrackInfoQuery trackInfoQuery) {
        Long userId = AuthContextHolder.getUserId();
        trackInfoQuery.setUserId(userId);
        IPage<TrackListVo> albumListVoPage = trackInfoMapper.findUserTrackPage(albumListVoIPage, trackInfoQuery);
        return albumListVoPage;
    }

    /**
     * 保存声音统计信息
     *
     * @param trackId  声音ID
     * @param statType 统计类型
     * @param statNum  统计数量: 初始默认为0
     */
    @Override
    public void saveTrackStat(Long trackId, String statType, Integer statNum) {
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }


    /**
     * 修改声音信息
     *
     * @param id        声音ID
     * @param trackInfo 声音修改信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackInfo(Long id, TrackInfoVo trackInfoVo) {
        //1 查询原音频文件信息
        TrackInfo preTrackInfo = trackInfoMapper.selectById(id);
        //1 判断音频文件是否需要变更
        //1.1 根据声音id查询旧音频文件标识
        if (!trackInfoVo.getMediaFileId().equals(preTrackInfo.getMediaFileId())) {
            //文件已重新上传,需要获取最新文件信息
            TrackMediaInfoVo trackMediaInfo = vodService.getTrackMediaInfo(trackInfoVo.getMediaFileId());
            if (trackMediaInfo != null) {
                //更新音频文件信息
                preTrackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
                preTrackInfo.setMediaType(trackMediaInfo.getType());
                preTrackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfo.getDuration()));
                preTrackInfo.setMediaSize(trackMediaInfo.getSize());
                preTrackInfo.setStatus(SystemConstant.TRACK_STATUS_REVIEWING);
                //todo: 文件更新后需要再次审核

                //1.2 删除云应用过期文件
                vodService.deleteMedia(preTrackInfo.getMediaFileId());
            }
        }
        BeanUtil.copyProperties(trackInfoVo, preTrackInfo);
        //2 更新数据库中音频文件信息
        trackInfoMapper.updateById(preTrackInfo);
    }

    /**
     * 删除声音信息
     *
     * @param id 声音ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTrackInfo(Long id) {
        //获得声音相关信息: 专辑ID,声音序号
        TrackInfo trackInfo = trackInfoMapper.selectById(id);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();
        //更新声音表序号
        trackInfoMapper.update(
                null,
                new LambdaUpdateWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        //大于该声音order_num记录序号均-1
                        .gt(TrackInfo::getOrderNum, orderNum)
                        .setSql("order_num = order_num - 1")
        );
        //删除声音表记录
        trackInfoMapper.deleteById(id);
        //删除声音统计信息
        trackStatMapper.delete(new LambdaUpdateWrapper<TrackStat>().eq(TrackStat::getTrackId, id));
        //更新专辑表声音数量
        albumInfoMapper.update(null, new LambdaUpdateWrapper<AlbumInfo>()
                .eq(AlbumInfo::getId, albumId)
                .setSql("include_track_count = include_track_count - 1"));
        //删除云应用音频文件
        vodService.deleteMedia(trackInfo.getMediaFileId());
    }

    /**
     * 分页获取专辑声音详情
     *
     * @param albumId 专辑id
     * @param page    分页参数
     * @param limit   分页参数
     * @return albumTrackListVoPage
     */
    @Override
    public Page<AlbumTrackListVo> findAlbumTrackPage(Page<AlbumTrackListVo> albumTrackListVoPage, Long albumId) {
        Long userId = AuthContextHolder.getUserId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Page<AlbumTrackListVo> albumTrackPage = trackInfoMapper.findAlbumTrackPage(albumTrackListVoPage, albumId);
        //专辑Vo信息列表,isShowPaidMark属性默认为false(非付费标识)
        List<AlbumTrackListVo> albumTrackListVoList = albumTrackPage.getRecords();
        //VIP免费专辑与付费专辑音频(除免费试听音频)默认为付费标识
        if (albumInfo.getPayType().equals("0102") || albumInfo.getPayType().equals("0103")) {
            albumTrackListVoList.stream()
                    .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                    .forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(true));
            albumTrackPage.setRecords(albumTrackListVoList);
        }

        //用户状态: 未登录      专辑付费类型: 0101免费/0102vip免费/0103付费
        if (userId == null) {
            //用户未登录: 可收听免费及试听音频
            return albumTrackPage;
        } else {
            //用户已登录: 获取用户信息
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            //判断是否需要查询用户音频购买信息: 普通用户->收听VIP免费和付费音频 ; VIP用户->收听付费音频
            boolean isVIP = false;
            if (userInfoVo.getIsVip().intValue() == 1 && userInfoVo.getVipExpireTime().after(new Date())) {
                isVIP = true;
            }
            boolean needCheck = false;
            if (isVIP && albumInfo.getPayType().equals("0103")) {
                //Vip用户但需要收听付费音频
                needCheck = true;
            } else if (isVIP && albumInfo.getPayType().equals("0102")) {
                //VIP用户收听Vip免费专辑,
                albumTrackListVoList.stream()
                        .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                        .forEach(albumTrackListVo -> albumTrackListVo.setIsShowPaidMark(false));
                return albumTrackPage.setRecords(albumTrackListVoList);
            } else if (!isVIP && (albumInfo.getPayType().equals("0103") || albumInfo.getPayType().equals("0102"))) {
                //非Vip用户但需要收听VIP免费或付费音频
                needCheck = true;
            }
            if (needCheck) {
                List<Long> trackIdList = albumTrackListVoList.stream()
                        .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                        .map(albumTrackListVo -> albumTrackListVo.getTrackId())
                        .collect(Collectors.toList());
                //查询用户购买专辑或专辑下声音信息
                Map<Long, Integer> trackPaidIdMap = userFeignClient.userIsPaidTrack(albumId, trackIdList).getData();
                //查询结果中用户拥有购买信息
                if (CollUtil.isNotEmpty(trackPaidIdMap)) {
                    albumTrackListVoList.stream()
                            .filter(albumTrackListVo -> albumTrackListVo.getOrderNum() > albumInfo.getTracksForFree())
                            .forEach(albumTrackListVo -> {
                                albumTrackListVo.setIsShowPaidMark(trackPaidIdMap.get(albumTrackListVo.getTrackId()) == 0);
                            });
                    return albumTrackPage.setRecords(albumTrackListVoList);
                }
            }
            return albumTrackPage;
        }
    }

    /**
     * 获取声音统计信息
     *
     * @param trackId 音频ID
     */
    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        TrackStatVo trackStatVo = trackStatMapper.getTrackStatVo(trackId);
        return trackStatVo;
    }

    @Autowired
    private AlbumStatMapper albumStatMapper;
    

    @Override
    public void updateStat(TrackStatMqVo trackStatMqVo) {
        //1.更新声音统计数值
        trackStatMapper.update(null,
                new LambdaUpdateWrapper<TrackStat>()
                        .eq(TrackStat::getTrackId, trackStatMqVo.getTrackId())
                        .eq(TrackStat::getStatType, trackStatMqVo.getStatType())
                        .setSql("stat_num = stat_num +" + trackStatMqVo.getCount())
        );
        //2.如果是声音播放、评论。还需要更新声音所属专辑统计数值
        if (SystemConstant.TRACK_STAT_PLAY.equals(trackStatMqVo.getStatType())) {
            albumStatMapper.update(null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, trackStatMqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_PLAY)
                            .setSql("stat_num = stat_num +" + trackStatMqVo.getCount())
            );
        }
        if (SystemConstant.TRACK_STAT_COMMENT.equals(trackStatMqVo.getStatType())) {
            albumStatMapper.update(null,
                    new LambdaUpdateWrapper<AlbumStat>()
                            .eq(AlbumStat::getAlbumId, trackStatMqVo.getAlbumId())
                            .eq(AlbumStat::getStatType, SystemConstant.ALBUM_STAT_COMMENT)
                            .setSql("stat_num = stat_num +" + trackStatMqVo.getCount())
            );
        }
    }

    @Override
    public List<TrackInfo> findPaidTrackInfoList(Long userId, Long trackId, Integer trackCount) {

        //1.根据选择声音ID查询声音，得到专辑ID跟序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Integer orderNum = trackInfo.getOrderNum();
        Long albumId = trackInfo.getAlbumId();

        //2.远程调用用户服务获取已购买声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();

        //2.获取指定数量未购买声音列表
        LambdaQueryWrapper<TrackInfo> queryWrapper = new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumId)
                .ge(TrackInfo::getOrderNum, orderNum)
                .last("limit " + trackCount)
                .select(TrackInfo::getId,TrackInfo::getTrackTitle, TrackInfo::getCoverUrl, TrackInfo::getAlbumId);
        if (CollUtil.isNotEmpty(userPaidTrackIdList)) {
            queryWrapper.notIn(TrackInfo::getId, userPaidTrackIdList);
        }
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(queryWrapper);
        return trackInfoList;
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long userId, Long trackId) {
        //1.根据声音ID查询到“起始”选择购买声音记录,获取专辑ID跟序号
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Long albumId = trackInfo.getAlbumId();
        Integer orderNum = trackInfo.getOrderNum();

        //2.根据"起始"声音序号+专辑ID获取所有“待购买”声音列表（可能包含已购买声音）
        List<TrackInfo> waitBuyTrackList = trackInfoMapper.selectList(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, albumId)
                        .ge(TrackInfo::getOrderNum, orderNum)
                        .select(TrackInfo::getId)
        );

        //3.远程调用用户服务获取已购买声音ID列表
        List<Long> userPaidTrackIdList = userFeignClient.findUserPaidTrackList(albumId).getData();
        if (CollUtil.isNotEmpty(userPaidTrackIdList)) {
            //4.如果存在已购声音ID，则将已购声音ID从待购买声音列表中移除，得到未购买声音数量
            waitBuyTrackList = waitBuyTrackList.stream()
                    .filter(track -> !userPaidTrackIdList.contains(track.getId()))
                    .collect(Collectors.toList());
        }
        //5.基于未购买声音数量，生成分集购买列表
        int size = waitBuyTrackList.size();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        BigDecimal price = albumInfo.getPrice();
        //5.1 创建分集购买集合List
        List<Map<String, Object>> list = new ArrayList<>();
        //5.2 构建"本集"分集购买对象
        Map<String, Object> currMap = new HashMap<>();
        currMap.put("name", "本集");
        currMap.put("price", price);
        currMap.put("trackCount", 1);
        list.add(currMap);
        //5.3 构建其他"后*集"分集购买对象   未购买数量：23    43
        for (int i = 10; i <= 50; i += 10) {
            Map<String, Object> map = new HashMap<>();
            if (size >= i) {
                map.put("name", "后" + i + "集");
                map.put("price", price.multiply(new BigDecimal(i)));
                map.put("trackCount", i);
                list.add(map);
            } else {
                map.put("name", "全集(后" + size + "集)");
                map.put("price", price.multiply(new BigDecimal(size)));
                map.put("trackCount", size);
                list.add(map);
                break;
            }
        }
        return list;
    }
}
